using System;
using FireStarterModeller.BO;
using FireStarterModeller.Logic;
using FireStarterModeller.Test.BO;
using NUnit.Framework;
using Rhino.Mocks;

namespace FireStarterModeller.Test.Logic
{
    [TestFixture]
    public class TestDMRelationshipPropertyDeleter
    {
        #region Setup/Teardown

        [SetUp]
        public virtual void SetupTest()
        {
            TestUtilsLogic.SetupTest();
        }

        [TearDown]
        public virtual void TearDownTest()
        {
        }

        #endregion

        [TestFixtureSetUp]
        public virtual void TestFixtureSetup()
        {
            TestUtilsLogic.SetupFixture();
        }

        [Test]
        public void Test_Construct_WhenRelationshipPropertyNull_ShouldRaiseError()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                new DMRelationshipPropertyDeleter(null);
                Assert.Fail("expected ArgumentNullException");
            }
                //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("relationshipProperty", ex.ParamName);
            }
        }

        [Test]
        public void Test_Delete_WhenPropertyNull_ShouldDeleteRelationshipProp()
        {
            //---------------Set up test pack-------------------
            IDMRelationshipProperty relationshipProperty = GetMockRelProp();
            relationshipProperty.RelatedProperty = GetMockProp();
            var relationshipDeleter = GetRepPropDeleter(relationshipProperty);
            //---------------Assert Precondition----------------
            Assert.IsNull(relationshipProperty.OwnerProperty);
            Assert.IsNotNull(relationshipProperty.RelatedProperty);
            //---------------Execute Test ----------------------
            relationshipDeleter.Delete();
            //---------------Test Result -----------------------
            relationshipProperty.AssertWasCalled(relProp => relProp.MarkForDelete());
        }

        [Test]
        public void Test_Delete_WhenRelatedPropertyNull_ShouldDeleteRelationshipProp()
        {
            //---------------Set up test pack-------------------
            IDMRelationshipProperty relationshipProperty = GetMockRelProp();
            relationshipProperty.OwnerProperty = GetMockProp();
            var relationshipDeleter = GetRepPropDeleter(relationshipProperty);
            //---------------Assert Precondition----------------
            Assert.IsNotNull(relationshipProperty.OwnerProperty);
            Assert.IsNull(relationshipProperty.RelatedProperty);
            relationshipProperty.AssertWasNotCalled(relProp => relProp.MarkForDelete());
            //---------------Execute Test ----------------------
            relationshipDeleter.Delete();
            //---------------Test Result -----------------------
            relationshipProperty.AssertWasCalled(relProp => relProp.MarkForDelete());
        }

        [Test]
        public void Test_Deleter_WhenPropertyPartOfObjectIdentity_ShouldNotDeleteProp()
        {
            //---------------Set up test pack-------------------
            IDMRelationshipProperty relationshipProperty = GetMockRelPropWithPropsSet();
            IDMProperty property =  relationshipProperty.OwnerProperty;

            SetIsPartOfObjectId(property, true);
            var relationshipDeleter = new DMRelationshipPropertyDeleter(relationshipProperty);

            //---------------Assert Precondition----------------
            Assert.IsNotNull(relationshipProperty.RelatedProperty);
            Assert.IsTrue(property.IsPartOfObjectIdentity);
            property.AssertWasNotCalled(prop => prop.MarkForDelete());
            //---------------Execute Test ----------------------
            relationshipDeleter.Delete();
            //---------------Test Result -----------------------
            property.AssertWasNotCalled(prop => prop.MarkForDelete());
            relationshipProperty.AssertWasCalled(relProp => relProp.MarkForDelete());
        }

        [Test]
        public void Test_Deleter_WhenPropertyNotPartOfObjectIdentity_ShouldDelete()
        {
            //---------------Set up test pack-------------------
            IDMRelationshipProperty relationshipProperty = GetMockRelPropWithPropsSet();
            IDMProperty property = relationshipProperty.OwnerProperty;

            var relationshipDeleter = new DMRelationshipPropertyDeleter(relationshipProperty);

            //---------------Assert Precondition----------------
            Assert.IsNotNull(relationshipProperty);
            Assert.IsFalse(property.IsPartOfObjectIdentity);
            relationshipProperty.AssertWasNotCalled(relProp => relProp.MarkForDelete());
            property.AssertWasNotCalled(prop => prop.MarkForDelete());
            //---------------Execute Test ----------------------
            relationshipDeleter.Delete();
            //---------------Test Result -----------------------
            relationshipProperty.AssertWasCalled(relProp => relProp.MarkForDelete());
            property.AssertWasCalled(prop => prop.MarkForDelete());
        }

        [Test]
        public void Test_Deleter_WhenRelatedPropertyPartOfObjectIdentity_ShouldNotDelete()
        {
            //---------------Set up test pack-------------------
            IDMRelationshipProperty relationshipProperty = GetMockRelPropWithPropsSet();
            IDMProperty ownerProperty = relationshipProperty.OwnerProperty;
            IDMProperty relatedProperty = relationshipProperty.RelatedProperty;
            SetIsPartOfObjectId(ownerProperty, true);
            SetIsPartOfObjectId(relatedProperty, true);
            var relationshipDeleter = new DMRelationshipPropertyDeleter(relationshipProperty);

            //---------------Assert Precondition----------------
            Assert.IsTrue(ownerProperty.IsPartOfObjectIdentity);
            Assert.IsTrue(relatedProperty.IsPartOfObjectIdentity);

            relationshipProperty.AssertWasNotCalled(relProp => relProp.MarkForDelete());
            relatedProperty.AssertWasNotCalled(prop => prop.MarkForDelete());
            //---------------Execute Test ----------------------
            relationshipDeleter.Delete();
            //---------------Test Result -----------------------
            relationshipProperty.AssertWasCalled(relProp => relProp.MarkForDelete());
            relatedProperty.AssertWasNotCalled(prop => prop.MarkForDelete());
        }

        [Test]
        public void Test_Deleter_WhenRelatedPropertyNotPartOfObjectIdentity_ShouldDelete()
        {
            //---------------Set up test pack-------------------
            IDMRelationshipProperty relationshipProperty = GetMockRelPropWithPropsSet();
            IDMProperty ownerProperty = relationshipProperty.OwnerProperty;
            IDMProperty relatedProperty = relationshipProperty.RelatedProperty;
            SetIsPartOfObjectId(ownerProperty, true);
            SetIsPartOfObjectId(relatedProperty, false);

            var relationshipDeleter = new DMRelationshipPropertyDeleter(relationshipProperty);

            //---------------Assert Precondition----------------
            Assert.IsNotNull(relationshipProperty.RelatedProperty);
            Assert.IsTrue(ownerProperty.IsPartOfObjectIdentity);
            Assert.IsFalse(relatedProperty.IsPartOfObjectIdentity);
            relationshipProperty.AssertWasNotCalled(relProp => relProp.MarkForDelete());
            relatedProperty.AssertWasNotCalled(prop => prop.MarkForDelete());
            //---------------Execute Test ----------------------
            relationshipDeleter.Delete();
            //---------------Test Result -----------------------
            relationshipProperty.AssertWasCalled(relProp => relProp.MarkForDelete());
            relatedProperty.AssertWasCalled(prop => prop.MarkForDelete());
        }
        [Test]
        public void Test_Deleter_WhenRelatedPropertyNotPartOfObjectIdentityAndOwnerPropNull_ShouldDelete()
        {
            //---------------Set up test pack-------------------
            IDMRelationshipProperty relationshipProperty = GetMockRelPropWithPropsSet();
            relationshipProperty.OwnerProperty = null;
            IDMProperty relatedProperty = relationshipProperty.RelatedProperty;
            SetIsPartOfObjectId(relatedProperty, false);

            var relationshipDeleter = new DMRelationshipPropertyDeleter(relationshipProperty);

            //---------------Assert Precondition----------------
            Assert.IsNotNull(relationshipProperty.RelatedProperty);
            Assert.IsFalse(relatedProperty.IsPartOfObjectIdentity);
            relationshipProperty.AssertWasNotCalled(relProp => relProp.MarkForDelete());
            relatedProperty.AssertWasNotCalled(prop => prop.MarkForDelete());
            //---------------Execute Test ----------------------
            relationshipDeleter.Delete();
            //---------------Test Result -----------------------
            relationshipProperty.AssertWasCalled(relProp => relProp.MarkForDelete());
            relatedProperty.AssertWasCalled(prop => prop.MarkForDelete());
        }

        private static IDMRelationshipProperty GetMockRelPropWithPropsSet()
        {
            IDMRelationshipProperty relationshipProperty = GetMockRelProp();
            relationshipProperty.OwnerProperty = GetMockProp();
            relationshipProperty.RelatedProperty = GetMockProp();
            return relationshipProperty;
        }

        private static void SetIsPartOfObjectId(IDMProperty property, bool isPartOf)
        {
            property.Stub(dmProperty => dmProperty.IsPartOfObjectIdentity).Return(isPartOf);
        }

        private static DMRelationshipPropertyDeleter GetRepPropDeleter(IDMRelationshipProperty relationshipProperty)
        {
            return new DMRelationshipPropertyDeleter(relationshipProperty);
        }

        private static IDMRelationshipProperty GetMockRelProp()
        {
            return MockRepository.GenerateStub<IDMRelationshipProperty>();
        }

        private static IDMProperty GetMockProp()
        {
            return MockRepository.GenerateStub<IDMProperty>();
        }
    }
}